/**
 * 
 */
package be.ipl.finito.utilitaires;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import javax.ws.rs.core.MultivaluedMap;

import be.ipl.finito.domaine.Joueur;
import be.ipl.finito.domaine.Partie;

/**
 * @author tantan
 * Fait le lient entre les id virtuel et l'id reel
 */
public class ListeParties implements Map<Partie, List<Joueur>> {


	private Map<Integer, Partie> parties;// < id interne : object partie >
	private Map<Integer, List<Joueur>> joueurs; // <id interne : list joueur present>
	private Map<Integer,Integer> mapping; // < id externe : id interne >

	/**
	 * 
	 */
	public ListeParties() {
		this.joueurs = new HashMap<Integer, List<Joueur>>();
		this.mapping = new TreeMap<Integer,Integer>();
		this.parties = new TreeMap<Integer,Partie>();

	}
	
	/**
	 * 
	 * Remplace la partie non persister par la partie persister dans la map
	 * @param partieOld
	 * @param partieNew
	 * @return la nouvelle partie
	 */
	public Partie lier(Partie partieOld, Partie partieNew){
		
		Integer idOld = partieOld.getId();
		Integer idNew = partieNew.getId();

		//Binding nouvelle id <---> idInterne
		mapping.put(idNew, idOld);
	
		
		//Retire l'ancienne version
		Partie partieEnlevee =parties.remove(idOld);
		
		if(partieEnlevee.getId()!=idOld) throw new InternalError("Probleme de liage");
		
		//Ajout la nouvelle version avec la meme idInterne
		parties.put(idOld, partieNew);

		return partieNew;
	}

	@Override
	public int size() {
		return parties.size();
	}

	@Override
	public boolean isEmpty() {
		return parties.isEmpty();
	}

	@Override
	public boolean containsKey(Object key) {
		return mapping.containsKey(((Partie) key).getId());
	}

	@Override
	public boolean containsValue(Object value) {
		throw new InternalError("UnImplemented");
	}

	@Override
	public List<Joueur> get(Object key) {		
		Integer idExterne =((Partie) key).getId();
		
		if(!mapping.containsKey(idExterne)) return null;
	
		Integer idInterne = mapping.get(idExterne);	

		return joueurs.get(mapping.get(idInterne));
	}

	@Override
	public List<Joueur> put(Partie key, List<Joueur> value) {
		Integer idExterne =((Partie) key).getId();
		if(mapping.containsKey(idExterne)) throw new RuntimeException("Partie deja presente dans la map");
		mapping.put(key.getId(), key.getId());
		joueurs.put(key.getId(), value);
		parties.put(key.getId(), key);

		return value;
	}

	@Override
	public List<Joueur> remove(Object key) {
		Integer idExterne=((Partie) key).getId();

		if(mapping.containsKey(idExterne)){
			//Suppression
			Integer idInterne = mapping.remove(idExterne);
			Partie p = parties.remove(idInterne);
			List<Joueur> listeJoueur = joueurs.remove(idInterne);
			
			//Suppression si multiple cle
			while(mapping.containsValue(idInterne)){
				//il reste une idExterne pour cette idInterne

				Set<Integer> idsExternes = mapping.keySet();
				for (Integer idExterneCourant : idsExternes) {
					if(mapping.get(idExterneCourant)==idInterne){
						mapping.remove(idExterneCourant);
						break;
					}
				}
			}
			return listeJoueur;
		}
		return null;
	}

	@Override
	public void putAll(Map<? extends Partie, ? extends List<Joueur>> m) {
		throw new InternalError("UnImplemented");

	}

	@Override
	public void clear() {
		parties.clear();
		joueurs.clear();
		mapping.clear();
	}

	@Override
	public Set<Partie> keySet() {
		return new HashSet<Partie>(parties.values());
	}

	@Override
	public Collection<List<Joueur>> values() {
		return joueurs.values();
	}

	@Override
	public Set<java.util.Map.Entry<Partie, List<Joueur>>> entrySet() {
		throw new InternalError("UnImplemented");
	}
	
	public boolean contientPartieId(Integer idExterne){
		return parties.containsKey(idExterne);	
	}

	//Verifie que le joueur est bien actif dans la partie
	public boolean contientJoueursId(int idPartie,Joueur joueur) {		
		if(!mapping.containsKey(idPartie)) return false;
		Integer idInterne = mapping.get(idPartie);
		
		return joueurs.get(idInterne).contains(joueur);
		
	}

	public Partie getPartieId(int idPartie) {
		if(!mapping.containsKey(idPartie)) return null;
		Integer idInterne = mapping.get(idPartie);
		return parties.get(idInterne);
	}

	public List<Joueur> getJoueursId(int idPartie) {
		if(!mapping.containsKey(idPartie)) return null;
		Integer idInterne = mapping.get(idPartie);
		return joueurs.get(idInterne);
	}

}
